package com.os.common.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.os.common.utils.dependent.SnowflakeID;

import java.lang.reflect.Array;
import java.util.*;

/**
 * 描述：我的工具类
 *
 * @author huxuehao
 **/
public class MyUtil {
    private static final String INT = "int";
    private static final String BIGINT = "bigint";
    private static final String DECIMAL = "decimal";
    private static final String DATE = "date";
    private static final String DATETIME = "datetime";
    private static final String VARCHAR = "varchar";

    public static String StringToMySqlType(String str) {
        if (isInt(str)) {
            return INT;
        } else if (isBigint(str)) {
            return BIGINT;
        } else if(isDecimal(str)) {
            return DECIMAL;
        } else if(isDatetime(str)) {
            return DATETIME;
        } else if (isDate(str)) {
            return DATE;
        } else {
            return VARCHAR;
        }
    }
    private static boolean isInt(String str) {
        return str != null && str.matches("^[1-9]\\d{1,10}$");
    }
    private static boolean isBigint(String str) {

        return str != null && str.matches("^[1-9][0-9]{11,19}$");
    }
    private static boolean isDecimal(String str) {

        return str != null && str.matches("^[1-9]*\\.[1-9]*$");
    }
    private static boolean isDate(String str) {
        if (str.matches("^[1-9][0-9]{3}-[0-9]{1,2}-[0-9]{1,2}$")){
            return true;
        } else if (str.matches("^[0-9]{1,2}-[0-9]{1,2}$")) {
            return true;
        } else if (str.matches("^[1-9][0-9]{3}/[0-9]{1,2}/[0-9]{1,2}$")){
            return true;
        } else if (str.matches("^[0-9]{1,2}/[0-9]{1,2}$")) {
            return true;
        } else if (str.matches("^[1-9][0-9]{3}年[0-9]{1,2}月[0-9]{1,2}日$")){
            return true;
        } else return str.matches("^[0-9]{1,2}月[0-9]{1,2}日$");
    }
    private static boolean isDatetime(String str) {
        if (str.matches("^[1-9][0-9]{3}-[0-9]{1,2}-[0-9]{1,2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2}||[1-9][0-9]{3}-[0-9]{1,2}-[0-9]{1,2}\\s[0-9]{2}:[0-9]{2}$")){
            return true;
        } else if (str.matches("^[1-9][0-9]{3}/[0-9]{1,2}/[0-9]{1,2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2}||[1-9][0-9]{3}/[0-9]{1,2}/[0-9]{1,2}\\s[0-9]{2}:[0-9]{2}$")){
            return true;
        } else {
            return str.matches("^[1-9][0-9]{3}年[0-9]{1,2}月[0-9]{1,2}日\\s[0-9]{2}时[0-9]{2}分[0-9]{2}秒||[1-9][0-9]{3}年[0-9]{1,2}月[0-9]{1,2}日\\s[0-9]{2}时[0-9]{2}分$");
        }
    }
    /**
     * KMP算法：匹配子串在父串中第一次出现的位置
     * @param parentStr 父串
     * @param subStr  子串
     * @return 第一次出现的位置的索引
     */
    public static Integer subStrFirAppearLocate(String parentStr, String subStr) {
        if(parentStr == null || subStr ==null) return -1;
        if(parentStr.length() < subStr.length()) return -1;
        if(parentStr.length() == subStr.length()) {
            /* 当长度相等且数值相等时 */
            if(parentStr.equals(subStr)) return 0;
            else return -1;
        }

        return getLocate(parentStr, subStr);
    }
    /**
     * 返回subStr在str中出现的首个位置
     * @param str     原字符串
     * @param subStr  目标字符串
     */
    private static int getLocate(String str, String subStr) {
        /* 记录“被匹配字符串”前移的位置数 */
        int locate = 0;
        /* 记录“被匹配字符串”前移后的字符串 */
        String afterMoveStr;

        /* 获取 str 和 subStr匹配成功的字符串 */
        String partStr = getSameStr(str, subStr, 0);
        /* 如果partStr（已匹配字符串） == subStr（匹配字符串），那么匹配成功 */
        while(!partStr.equals(subStr)) {
            /* 如果已匹配的字符串的长度小于2，那么不可能产生“部分匹配值”，既需要“被匹配字符串”前移1位即可 */
            if(partStr.length() <= 1) {
                locate++;
                afterMoveStr = str.substring(locate); /* “被匹配字符串”前移1位即可 */
                /* 如果前移后的字符串长度小于“匹配字符串”，既为匹配失败，否自继续匹配 */
                if(afterMoveStr.length()>=subStr.length())
                    partStr = getSameStr(afterMoveStr, subStr, 0);
                else
                    return -1;
            }else { /* 如果已匹配的字符串的长度大于2，那么可能产生“部分匹配值” */
                /* /获取"部分匹配值" */
                int partialMatchVal = getPartialMatchVal(partStr);
                /* 计算“被匹配字符串”一共需要前移的位置 */
                locate += (partStr.length()-partialMatchVal);
                afterMoveStr = str.substring(locate); /* 前移 */
                /* 如果前移后的字符串长度小于“匹配字符串”，既为匹配失败，否自继续匹配 */
                if(afterMoveStr.length()>=subStr.length())
                    /* 获取afterMoveStr与subStr字符串相同字符串 */
                    partStr = getSameStr(afterMoveStr, subStr,partialMatchVal);
                else
                    return -1;
            }
        }
        return locate;
    }
    /**
     * 计算"部分匹配值"
     * @param partStr ： 已匹配的字符串
     */
    private static int getPartialMatchVal(String partStr) {
        int nums = 0; /* 存放"部分匹配值" */
        List<String> list1 = new ArrayList<>(); /* 存放所有的前缀 */
        List<String> list2 = new ArrayList<>(); /* 存放所有的后缀 */
        /* 从头到尾和从尾到头进行扫描（排除首尾的扫描） */
        for (int i=0,j=partStr.length()-1; i<partStr.length()-1 && j>0; i++,j--) {
            list1.add(partStr.substring(0, i+1)); /* 获取前缀字符串 */
            list2.add(partStr.substring(j)); /* 获取后缀字符串 */
        }
        /* 比较最大相同前缀（部分匹配值） */
        for (int i = 0; i < list1.size(); i++) {
            if(list1.get(i).equals(list2.get(i)) && list1.get(i).length()>nums) {
                nums = list1.get(i).length();
            }
        }
        return nums;
    }
    /**
     * 计算str  和  subStr 中已匹配的字符串
     * @param str ： 被匹配字符串
     * @param subStr 匹配字符串
     * @param partialMatchVal 开始时匹配的位置
     */
    private static String getSameStr(String str, String subStr, int partialMatchVal) {
        /* 根据KMP算法的特点，索引0~（partialMatchVal-1）的字符串肯定是相等的，先将其加入sameStr */
        String sameStr = subStr.substring(0,partialMatchVal);

        /* 从索引partialMatchVal开始比较两个字符串，如果有相等的字符，则追加到sameStr中。 */
        for (int i = partialMatchVal; i < subStr.length(); i++) {
            if(str.charAt(i) == subStr.charAt(i)) {
                sameStr += subStr.charAt(i);
            }else {
                break;
            }
        }
        return sameStr;
    }

    /**
     * 匹配子串在父串中最后一次出现的位置
     * @param parentStr 父串
     * @param subStr 子串
     * @return 最后一次出现的位置的索引
     */
    public static Integer subStrLastAppearLocate(String parentStr, String subStr){
        if (parentStr == null || subStr == null) {
            return -1;
        }
        int index = 0;
        String[] split = parentStr.split(subStr);
        int size = split.length;
        if (parentStr.endsWith(subStr)){ /* 子串在末尾 */
            return parentStr.length()-subStr.length();
        } else if (size == 1) { /* 父串中只存在一个子串 */
            if (parentStr.startsWith(subStr)){ /* 子串在头 */
                return 0;
            } else {  /* 子串在尾 */
                return split[0].length();
            }
        } else if(size == 2){ /* 存在一个子串在中间 */
            return split[0].length();
        } else { /* 存在多个子串 */
            for (int i =0 ;i < size-1; i++) {
                index += split[i].length();
            }
            index += (size-2)*(subStr.length());
        }
        return index;
    }

    /**
     * 判断对象是否为空
     */
    public static Boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof String) {
            return ((String) obj).trim().length() == 0;
        }
        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }
        if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }
        if (obj instanceof Optional) {
            return !((Optional<?>)obj).isPresent();
        }
        if (obj instanceof CharSequence) {
            return ((CharSequence)obj).length() == 0;
        }
        return false;
    }

    /**
     * 判断是否有空
     */
    public static boolean hasEmpty(Object... os) {
        for (Object o : os) {
            if (isEmpty(o)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 生成唯一的雪花ID
     */
    public static String nextId() {
        return String.valueOf(SnowflakeID.nextId());
    }

    /**
     * 对象转map
     */
    public static Map<String,Object> ObjectToMap(Object o) {
        return JSON.parseObject(JSON.toJSONString(o), new TypeReference<Map<String, Object>>(){});
    }

}
